import random
import re
import time

from django import http
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection

from libs.captcha.captcha import captcha
from libs.yuntongxun.sms import CCP
from users.models import User
from utils import meiduo_signature
from . import constants
from utils.response_code import RETCODE, err_msg


class ImageCodeView(View):
    def get(self, request, image_code_id):
        # 1, 接收数据
        pass

        # 2, 校验数据
        pass

        # 3, 处理业务
        # 获取图片文本内容和图片二进制代码
        text, image = captcha.generate_captcha()

        # 把uuid和图片文本存入redis
        # 获取redis客户端
        redis_client = get_redis_connection('verify_code')
        # 写入redis
        redis_client.setex(image_code_id, constants.REDIS_IMAGE_CODE_EXPIRE, text)

        # 4, 返回响应
        return HttpResponse(image, content_type='image/jpg')
        pass


class SmsCodeView(View):
    def get(self, request, mobile):
        # 1, 接收数据
        data = request.GET
        image_code = data.get('image_code')
        image_code_id = data.get('image_code_id')

        # 2, 校验数据
        if not all([mobile, image_code, image_code_id]):
            return JsonResponse({'code': RETCODE.NECESSARYPARAMERR, 'errmsg': '参数不全'})

        if not re.match(r'^1[3456789]\d{9}$', mobile):
            return JsonResponse({'code': RETCODE.MOBILEERR, 'errmsg': '手机格式不正确'})

        # 根据redis中保存的内容 判断图形验证码是否正确
        # 创建redis链接
        redis_client = get_redis_connection('verify_code')
        redis_code = redis_client.get(image_code_id)  # bytes
        if redis_code:
            # bytes 转成 string
            redis_code = redis_code.decode()
            # 从redis中删除这个图片验证码, 以防再次被使用
            redis_client.delete(image_code_id)

        # 比较用户提供的图片内容是否和redis中保存的一致
        if image_code.upper() != redis_code:
            return JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '图片验证码不正确'})

        # 3, 处理业务
        # # 判断是否频繁发送了
        # # 从redis 中取一下这个手机号是否60秒内发送过短信,
        redis_flag = redis_client.get('flag_%s' % mobile)
        if redis_flag:
            # 如果取到了, 则60秒内发送过
            return JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '短信频繁发送!'})

        # 生成短信验证码
        sms_code = "%04s" % random.randint(0, 9999)
        # 验证码保存到redis中
        # redis_client.setex(mobile, constants.REDIS_SMS_CODE_EXPIRE, sms_code)
        # redis_client.setex('flag_%s'%mobile, constants.REDIS_SENDING_SMS_CODE_EXPIRE, 1)  # flag_13312341234  :  1

        # 改造使用pipeline 来执行redis指令, 用来提高执行速度
        pl = redis_client.pipeline()
        pl.setex(mobile, constants.REDIS_SMS_CODE_EXPIRE, sms_code)
        pl.setex('flag_%s' % mobile, constants.REDIS_SENDING_SMS_CODE_EXPIRE, 1)  # flag_13312341234  :  1
        pl.execute()

        # 发送短信
        # time.sleep(5)
        # ccp = CCP()
        # ccp.send_template_sms(mobile, [sms_code, constants.REDIS_SMS_CODE_EXPIRE//60], 1)
        # 调用celery方法, 异步发送短信
        # from main import send_sms_code
        # send_sms_code.delay(mobile, sms_code, constants.REDIS_SMS_CODE_EXPIRE//60)
        print(sms_code)

        # 4, 返回响应
        res = {
            'code': 0,
            'errmsg': '成功'
        }
        return JsonResponse(res)

        pass


class PwdCodeView(View):
    def get(self, request, username):

        # 接收
        uuid = request.GET.get('image_code_id')
        image_code = request.GET.get('text')
        # 2.图形验证码是否正确
        # 2.1从redis中读取之前保存的图形验证码文本
        redis_cli_image = get_redis_connection('verify_code')
        image_code_redis = redis_cli_image.get(uuid)
        # 2.2如果redis中的数据过期则提示
        if image_code_redis is None:
            return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '图形验证码已过期，点击图片换一个'})

        # 2.3立即删除redis中图形验证码，表示这个值不能使用第二次
        redis_cli_image.delete(uuid)
        # 2.3对比图形验证码：不区分大小写
        if image_code_redis.decode().lower() != image_code.lower():
            return http.JsonResponse({'code': RETCODE.IMAGECODEERR, 'errmsg': '图形验证码错误'})
        try:
            user = User.objects.get(username=username)
        except:
            return http.JsonResponse({}, status=404)

        # 处理

        json_str = meiduo_signature.dumps({"user_id": user.id, 'mobile': user.mobile}, 300)

        return http.JsonResponse({'mobile': user.mobile, 'access_token': json_str})


class PwdSMSCodeView(View):
    def get(self, request):

        access_token = request.GET.get('access_token')

        user_dict = meiduo_signature.loads(access_token, 300)

        if user_dict is None:
            return http.JsonResponse({}, status=400)

        mobile = user_dict['mobile']
        try:
            User.objects.get(mobile=mobile)
        except:
            return http.JsonResponse({}, status=400)

        # 验证
        redis_cli_sms = get_redis_connection('verify_code')
        # 0.是否60秒内
        if redis_cli_sms.get(mobile + '_flag') is not None:
            return http.JsonResponse({'code': RETCODE.SMSCODERR, 'errmsg': '发送短信太频繁，请稍候再发'})

        # # 处理
        # # 1.生成随机6位数
        sms_code = '%06d' % random.randint(0, 999999)
        print(sms_code)
        # 优化：使用管道
        redis_pl = redis_cli_sms.pipeline()
        redis_pl.setex(mobile, constants.REDIS_SMS_CODE_EXPIRE, sms_code)
        redis_pl.setex(mobile + '_flag', constants.REDIS_SENDING_SMS_CODE_EXPIRE, 1)
        redis_pl.execute()
        # 3.发短信
        # 通过delay调用，可以将任务加到队列中，交给celery去执行
        # send_sms.delay(mobile, sms_code)
        print(sms_code)
        # 响应
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})


class PwdCheckCodeView(View):
    def get(self, request, username):

        sms_code = request.GET.get('sms_code')

        try:
            user = User.objects.get(username=username)
        except:
            return http.JsonResponse({}, status=400)

        # 短信验证码
        # 1.读取redis中的短信验证码
        redis_cli = get_redis_connection('verify_code')
        sms_code_redis = redis_cli.get(user.mobile)
        # 2.判断是否过期
        if sms_code_redis is None:
            return http.HttpResponseForbidden('短信验证码已经过期')
        # 3.删除短信验证码，不可以使用第二次
        redis_cli.delete(user.mobile)
        redis_cli.delete(user.mobile + '_flag')
        # 4.判断是否正确
        if sms_code_redis.decode() != sms_code:
            return http.HttpResponseForbidden('短信验证码错误')

        json_str = meiduo_signature.dumps({"user_id": user.id, 'mobile': user.mobile}, 300)
        return http.JsonResponse({'user_id': user.id, 'access_token': json_str})
